package com.unsins.core.utils;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import net.sf.json.util.JSONStringer;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.util.Assert;

/**
 * 扩展Apache Commons BeanUtils, 利用他的反射功能构造json字符串。
 */
public final class AjaxUtils extends BeanUtils {
	protected static final Logger logger = Logger.getLogger(AjaxUtils.class);

	/**
	 * 获得field的getter函数名称.
	 */
	private static String getGetterName(Class type, String fieldName) {
		Assert.notNull(type, "Type required");
		Assert.hasText(fieldName, "FieldName required");

		if (type.getName().equals("boolean")) {
			return "is" + StringUtils.capitalize(fieldName);
		} else {
			return "get" + StringUtils.capitalize(fieldName);
		}
	}

	/**
	 * 获得field的getter函数,如果找不到该方法,返回null.
	 */
	private static Method getGetterMethod(Class type, String fieldName, Class fldType) {
		try {
			if (fieldName.equals("serialVersionUID"))
				return null;

			String methodName = getGetterName(fldType, fieldName);
			return type.getMethod(methodName, null);
		} catch (NoSuchMethodException e) {
			if (logger.isDebugEnabled()) {
				logger.error(fieldName + ":NoSuchMethodException");
			}
		}

		return null;
	}

	/*
	 * 把用户指定的类转换成json字符串。 @param obj 用户指定的转换类 @return json的字符串
	 */
	public static String toJsonString(JSONStringer json, Object obj) {
		if (obj == null)
			return "";

		json.object();
		final Object tempObj = obj;
		List array = getDeclaredFields(obj);

		Object strValue = null;
		Field fld = null;
		try {
			for (int i = 0; i < array.size(); i++) {
				fld = (Field) array.get(i);
				String strFieldName = fld.getName();
				Method method = getGetterMethod(tempObj.getClass(), fld.getName(), fld.getType());

				strValue = null;
				if (method != null)
					strValue = method.invoke(tempObj, null);

				if (strValue == null)
					strValue = "";

				json.key(strFieldName);
				if (fld.getType().getName().startsWith("com.esoft.domain")) {
					json.value(strValue);
				} else {
					json.value(strValue.toString());
				}
			}
		} catch (IllegalArgumentException ex) {
			if (logger.isDebugEnabled())
				logger.error("IllegalArgumentException");
		} catch (InvocationTargetException ex) {
			if (logger.isDebugEnabled())
				logger.error("InvocationTargetException");
		} catch (IllegalAccessException ex) {
			if (logger.isDebugEnabled())
				logger.error("IllegalAccessException");
		}

		json.endObject();
		return json.toString();
	}

	/**
	 * 循环向上转型,获取对象的DeclaredFields.
	 * 
	 */
	private static List getDeclaredFields(final Object obj) throws SecurityException {
		List array = new ArrayList();

		for (Class superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
			Field fds[] = superClass.getDeclaredFields();
			for (int i = 0; i < fds.length; i++) {
				array.add(fds[i]);
			}
		}

		return array;
	}

	/**
	 * 把用户指定的对象列表转换成jsonarray.
	 * 
	 * @param objectLst
	 *            用户指定的对象列表
	 * @return json的Array字符串
	 */
	public static String toJsonArray(final List objectLst) {
		if (objectLst == null)
			return "[]";

		JSONStringer json = new JSONStringer();
		json.array();
		final List array = new ArrayList(objectLst);

		for (int i = 0; i < array.size(); i++) {
			toJsonString(json, array.get(i));
		}

		json.endArray();
		return json.toString();
	}

	/**
	 * 以UTF-8的字符编码，在用户指定的OutputStream中写入Json字符串
	 * 
	 * @param os
	 *            输出流
	 * @param sendBody
	 *            用户指定的输出文本
	 */
	public static void sendJsonText(final OutputStream os, String sendBody) {
		sendJsonText(os, sendBody, "UTF-8");
	}

	/**
	 * 以encoding的字符编码，在用户指定的OutputStream中写入Json字符串
	 * 
	 * @param os
	 *            输出流
	 * @param sendBody
	 *            用户指定的输出文本
	 * @param encoding
	 *            用户指定的编码集
	 */
	public static void sendJsonText(final OutputStream os, String sendBody, String encoding) {
		try {
			os.write(sendBody.getBytes(encoding));
		} catch (IOException e) {
			if (logger.isDebugEnabled()) {
				logger.error(e);
			}
		}
	}
}
